package org.flexthinker.binding.form.support
{
    import org.flexthinker.binding.validation.FormModelValidator;
    import org.flexthinker.binding.validation.ValidationResultsModel;
    import org.flexthinker.binding.validation.support.MockValidatorsHolder;
    import org.flexthinker.binding.validation.support.RulesValidator;
    import org.flexthinker.binding.validation.support.ValidationListenerCounter;
    import org.flexthinker.binding.value.support.MockBean;

    import mx.events.ValidationResultEvent;

    import mx.utils.ObjectUtil;

    import org.hamcrest.assertThat;
    import org.hamcrest.assertThatBoolean;
    import org.hamcrest.object.equalTo;

    /**
     *
     */
    public class DefaultValidatingFormModelTest
    {
        private var fm:DefaultValidatingFormModel;
        private var bean:MockBean;

        private var bindablePropVL:ValidationListenerCounter;
        private var vl:ValidationListenerCounter;

        private var formValidator:FormModelValidator;

        public function DefaultValidatingFormModelTest()
        {
        }

        [Before]
        public function setUp():void
        {
            bean = new MockBean();
            fm = new DefaultValidatingFormModel( bean );
            formValidator = new RulesValidator( new MockValidatorsHolder().getValidators() );
            vl = new ValidationListenerCounter();
            bindablePropVL = new ValidationListenerCounter();
        }

        [Test]
        public function testDefaultValues():void
        {
            var resultsModel:ValidationResultsModel = fm.getValidationResults();
            assertThat( "getValidationResults() should exist", resultsModel != null, equalTo( true ) );

            assertThat( "validationResults shouldn't have errors initially", resultsModel.getHasErrors(), equalTo( false ) );
            assertThat( "validationResults shouldn't have warning initially", resultsModel.getHasWarnings(), equalTo( false ) );
            assertThat( "validationResults shouldn't have infos initially", resultsModel.getHasInfo(), equalTo( false ) );

            assertThat( "should be validating be default", fm.isValidating(), equalTo( true ) );
            assertThat( "validator shouldn't be null by default", fm.getValidator() != null, equalTo( true ) );

            fm.setValidator( formValidator );
            assertThat( "validator should have been updated", fm.getValidator(), equalTo( formValidator ) );
        }

        [Test]
        public function testValidationWhenBeanChanges():void
        {
            fm.getValidationResults().addValidationListener( vl );
            fm.getValidationResults().addValidationListenerForProperty( "bindableProperty", bindablePropVL );
            fm.add( "bindableProperty" );
            fm.add( "bindablePropertyWithCustomEvent" );
            fm.add( "simpleInt" );

            fm.setValidator( formValidator );

            assertThat( "form shouldn't be valid", fm.getValidationResults().getHasErrors(), equalTo( true ) );

            var bindablePropertyMessages:Vector.<ValidationResultEvent> = fm.getValidationResults().getMessagesForProperty( "bindableProperty" );
            var bindProp2:Vector.<ValidationResultEvent> = fm.getValidationResults().getMessagesForProperty( "bindablePropertyWithCustomEvent" );
            assertThat( "validation messages for 'bindableProperty' are wrong", bindablePropertyMessages.length, equalTo( 1 ) );
            assertThat( "validation of 'bindableProperty' is wrong", bindablePropertyMessages[0].type,
                        equalTo( ValidationResultEvent.INVALID ) );
            assertThat( "validaton of 'bindablePropertyWithCustomEvent' is wrong", bindProp2[0].type,
                        equalTo( ValidationResultEvent.VALID ) );
            assertThat( "validation listener should have been called", vl.counter, equalTo( 1 ) );
            assertThat( "validation listener for property should have been called", bindablePropVL.counter, equalTo( 1 ) );

            bean.bindableProperty = "I HAVE VALUE.I'M MAKING THE FORM VALID";
            bean.simpleInt = 10;

            assertThat( "form should be valid now.It should update to bean's changes", fm.getValidationResults().getHasErrors(),
                        equalTo( false ) );
            assertThat( "validation listener should have been called", vl.counter, equalTo( 3 ) );
            assertThat( "validation listener for 'bindableProperty' should have been called", bindablePropVL.counter, equalTo( 3 ) );

        }

        [Test]
        public function testValidationWhenValueModelChange():void
        {
            fm.getValidationResults().addValidationListener( vl );
            fm.getValidationResults().addValidationListenerForProperty( "bindableProperty", bindablePropVL );
            fm.add( "bindableProperty" );
            fm.add( "bindablePropertyWithCustomEvent" );

            fm.setValidator( formValidator );

            assertThat( "form shouldn't be valid", fm.getValidationResults().getHasErrors(), equalTo( true ) );

            fm.getValueModel( "bindableProperty" ).setValue( "I HAVE VALUE.I'M MAKING THE FORM VALID" );

            assertThat( "form should be valid now.It should update to bean's changes", fm.getValidationResults().getHasErrors(),
                        equalTo( false ) );
            assertThat( "validation listener should have been called", vl.counter, equalTo( 2 ) );
            assertThat( "validation listener for property should have been called", bindablePropVL.counter, equalTo( 2 ) );
        }

        [Test]
        public function testIsCommitable():void
        {
            fm.getValidationResults().addValidationListener( vl );
            fm.getValidationResults().addValidationListenerForProperty( "bindableProperty", bindablePropVL );
            fm.add( "bindableProperty" );
            fm.add( "bindablePropertyWithCustomEvent" );
            fm.add( "simpleInt" );

            fm.setValidator( formValidator );

            assertThat( "form shouldn't be valid", fm.isCommittable(), equalTo( false ) );

            bean.bindableProperty = "I'm VALID, but simpleInt is NOT";
            assertThat( "form shouldn't be valid YET", fm.isCommittable(), equalTo( false ) );

            bean.simpleInt = 10;
            //trace( ObjectUtil.toString( fm.getValidationResults().getMessages() ) );
            assertThat( "form should be valid now", fm.isCommittable(), equalTo( true ) );

        }


    }
}